﻿using System;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;


using AIthin.Neuro;

namespace AIthin.Controls
{
    public partial class StructViewControl : UserControl
    {
        /// <summary>
        /// rendering device 
        /// </summary>
        Device device = null;
        /// <summary>
        /// rendered network
        /// </summary>
        INetwork network = null;
        /// <summary>
        /// vertexbuffer for network
        /// </summary>
        VertexBuffer vertexBuffer = null;
        VertexBuffer lineVertexBuffer = null;
        /// <summary>
        /// Index buffer for network
        /// </summary>
        IndexBuffer indexBuffer = null;
        IndexBuffer lineIndexBuffer = null;
        /// <summary>
        /// Vertexes array
        /// </summary>
        CustomVertex.PositionColored[] v;
        CustomVertex.PositionColored[] v1;
        int lineVertexCount = 20;
        int VertexCount;
        /// <summary>
        /// Indexes
        /// </summary>
        int[] index;
        int[] lineIndex;
        int IndexCount;
        int lineIndexCount = 20;
        /// <summary>
        /// camera position
        /// </summary>
        Vector3 CameraPosition = new Vector3(0f, 0f, 0f);
        /// <summary>
        /// target vector for a camera
        /// </summary>
        Vector3 CameraLookAt = new Vector3(0f, 0f, 0f);
        /// <summary>
        /// view direction
        /// </summary>
        Vector3 CamLockal = new Vector3(0f, 0f, 30f);
        /// <summary>
        /// schift for changet view
        /// </summary>
        float SchiftX = 0f, SchiftY = 0f;
        /// <summary>
        /// vector for top of the camera
        /// </summary>
        Vector3 CameraUp = new Vector3(-1f, 0f, 0f);
        /// <summary>
        /// current view position
        /// </summary>
        Matrix ViewMatrix;
        /// <summary>
        /// camera angle to X Achse and to Y Achse (radian)
        /// </summary>
        double AngleX = 0.0f, AngleY = 0.0f;
        Point LastRenderedPoint;
        float ViewScale = 1.0f;
        bool KeyShift_Down = false;
        /// <summary>
        /// coordinats a center of weights 
        /// </summary>
        float Xw, Yw, Zw;
        /// <summary>
        /// event from RealityControl
        /// </summary>
        public event RealityControl.TickComputed netTickComputed;
        /// <summary>
        /// konstructor for a Structview Control
        /// </summary>
        public StructViewControl()
        {
            InitializeComponent();
            this.MouseWheel += new MouseEventHandler(MouseWheelHandler);
        }
        /// <summary>
        /// init with NeuroControl
        /// </summary>
        /// <param name="nc">Control where exist NeuroNetwork to draw</param>
        public StructViewControl(ref NeuroControl nc)
            : this()
        {
            network = (INetwork)nc.network;
            //add parent nc control even handler for redraw
            //TODO what happen by dispose parent nc control?
            nc.networkTickComputed += new NeuroControl.TickComputed(handleTickComputed);
            fillBuffers();
            //first view
            CameraLookAt = new Vector3(Xw, Yw, Zw);
            CameraPosition = new Vector3(Xw, Yw, Zw - 30.0f);
            ViewMatrix = Matrix.LookAtLH(CameraPosition, CameraLookAt, CameraUp);
        }
        /// <summary>
        /// init with Network
        /// </summary>
        /// <param name="nw">NeuroNetwork to draw</param>
        public StructViewControl(ref Network nw) : this()
        {
            network = (INetwork)nw;
            //add parent nc control even handler for redraw
            //TODO what happen by dispose parent nc control?
            // nc.networkTickComputed += new NeuroControl.TickComputed(handleTickComputed);
            fillBuffers();
            //first view
            CameraLookAt = new Vector3(Xw, Yw, Zw);
            CameraPosition = new Vector3(Xw, Yw, Zw - 30.0f);
            ViewMatrix = Matrix.LookAtLH(CameraPosition, CameraLookAt, CameraUp);
        }
        /// <summary>
        /// load network data from NeuroControl
        /// </summary>
        /// <param name="nc">Control with network to visualise</param>
        /// <returns>return true whenn successful</returns>
        public bool LoadNetwork(ref NeuroControl nc)
        {
            network = nc.network;
            //add parent nc control event handler for redraw
            nc.networkTickComputed += new NeuroControl.TickComputed(handleTickComputed);
            fillBuffers();
            CameraLookAt = new Vector3(Xw, Yw, Zw);
            CameraPosition = new Vector3(Xw, Yw, Zw - 30.0f);
            ViewMatrix = Matrix.LookAtLH(CameraPosition, CameraLookAt, CameraUp);

            if (!this.InitializeGraphics()) // Direct3D initialisieren 
            {
                MessageBox.Show("Konnte Hardware nicht initialisieren.");
            }
            return true;
        }
        public bool LoadNetwork(ref INetwork nw)
        {
            //TODO Make Interface
            network = nw;
            //add parent nc control event handler for redraw
            //TODO what happen by dispose parent nc control?
            netTickComputed += new RealityControl.TickComputed(handleTickComputed);
            fillBuffers();
            CameraLookAt = new Vector3(Xw, Yw, Zw);
            CameraPosition = new Vector3(Xw, Yw, Zw - 30.0f);
            ViewMatrix = Matrix.LookAtLH(CameraPosition, CameraLookAt, CameraUp);

            if (!this.InitializeGraphics()) // Direct3D initialisieren 
            {
                MessageBox.Show("Konnte Hardware nicht initialisieren.");
            }
            return true;
        }
        /// <summary>
        /// fill Vertex and index arrays with data need for rendering
        /// </summary>
        private void fillBuffers()
        {
            if (network == null)
            {
                //TODO make a try 
                Exception NetworkEx = new Exception("no network assigned!");
                return;
            }
            // 4 points per neuron
            VertexCount = network.NeuronsCount * 4;
            // 12 vertex sequenses to draw neuron 3 per face
            IndexCount = network.NeuronsCount * 12;
            //create Array
            v = new CustomVertex.PositionColored[VertexCount];
            //create index Array for drawing
            index = new int[IndexCount];
            //set vertex sequense for the array
            short[] VertexSequence = new short[] { 0, 2, 1, 1, 2, 3, 0, 3, 2, 0, 1, 3 };
            //Size of neuron
            float Size = 0.2f;
            //calculate vertex coordinates and set to array
            
            int activeColor;

            Xw = Yw = Zw = 0f;
            
            for (int i = 0, k = 0; i < network.NeuronsCount; i++)
            {
                //RES optimize speed
                //first vertex

                if (network[i].Activated)
                    activeColor = System.Drawing.Color.Yellow.ToArgb();
                else
                    activeColor = System.Drawing.Color.BlueViolet.ToArgb();

                v[k].X = network[i].X - Size / 2;
                v[k].Y = network[i].Y + 0f;
                v[k].Z = network[i].Z + 0f;
                v[k].Color = activeColor;

                k++;
                v[k].X = network[i].X + 0f;
                v[k].Y = network[i].Y + Size;
                v[k].Z = network[i].Z + 0f;
                v[k].Color = activeColor;

                k++;
                v[k].X = network[i].X + Size / 2;
                v[k].Y = network[i].Y + 0f;
                v[k].Z = network[i].Z + 0f;
                v[k].Color = activeColor;

                k++;
                v[k].X = network[i].X + 0f;
                v[k].Y = network[i].Y + 0f;
                v[k].Z = network[i].Z + 2 * Size;
                v[k].Color = activeColor;

               
                k++;
                //calc weight center
                Xw += network[i].X;
                Yw += network[i].Y;
                Zw += network[i].Z;
            }

            Xw /= network.NeuronsCount;
            Yw /= network.NeuronsCount;
            Zw /= network.NeuronsCount;

            //set index number for triangles
            for (int m = 0; m < IndexCount; m += 12)
            {
                for (int i = 0; i < 12; i++)
                    //TODO 3 wechseln
                    index[m + i] = VertexSequence[i] + m / 3;
            }

           drawNeuronConnections(network.NeuronsCount - 1);
        }
        private void drawNeuronConnections(int NeuronConn)
        {
            int[] inputNeurons;
            float[] inputWeights;

            network[NeuronConn].getInputs(out inputNeurons, out inputWeights);
            lineVertexCount = inputNeurons.Length + 1;
            lineIndexCount = 2 * inputNeurons.Length;
            v1 = new CustomVertex.PositionColored[lineVertexCount];
            lineIndex = new int[lineIndexCount];

            v1[0].X = network[NeuronConn].X;
            v1[0].Y = network[NeuronConn].Y;
            v1[0].Z = network[NeuronConn].Z;
            v1[0].Color = System.Drawing.Color.FromArgb(0,0, 0, 0).ToArgb();

            int p = 0;
            for (int m = 1; m < inputNeurons.Length + 1; m++)
            {
                if (inputNeurons[m - 1] == 0)
                {
                    int u = 1;
                    Debug.WriteLine("neuron " + NeuronConn.ToString()
                               + " input " + (m - 1).ToString() + " ist 0"); 
                }
                v1[m].X = network[inputNeurons[m - 1]].X;
                v1[m].Y = network[inputNeurons[m - 1]].Y;
                v1[m].Z = network[inputNeurons[m - 1]].Z;
                v1[m].Color = weightToColor(inputWeights, m-1);

                lineIndex[p++] = 0;
                lineIndex[p++] = m;
            }
        }

        private static int weightToColor(float[] inputWeights, int m)
        {
            return System.Drawing.Color.FromArgb(0, 0, 125 * ((int)inputWeights[m] + 1), 0).ToArgb();
        }

        /// <summary>
        /// Calculate camera position and render
        /// </summary>
        private void calcAndRenderNewCameraPosition()
        {
            //always initial direction direction Z axis
            CamLockal.X = SchiftX;
            CamLockal.Y = SchiftY;
            CamLockal.Z = -30f;
            //transform vector 
            CamLockal.TransformNormal(Matrix.RotationX((float)AngleX));
            //U Matrix rotation at Y
            CamLockal.TransformNormal(Matrix.RotationY((float)AngleY));
            //calc camera position for new view direction
            CameraPosition = CamLockal + CameraLookAt;
            //set viewmatrix
            ViewMatrix = Matrix.LookAtLH(CameraPosition, CameraLookAt, CameraUp);
            /*
                        ViewMatrix *= Matrix.Translation(-CameraLookAt);
                        ViewMatrix *= Matrix.RotationX((float)AngleX);
                        ViewMatrix *= Matrix.RotationY((float)AngleY);
                        ViewMatrix *= Matrix.Translation(CameraLookAt);
            */

            Render();
        }
        private bool InitializeGraphics()
        {
            if (this.Disposing) return false;

            try
            {
                // Die Hardware initialisieren und ein paar Parameter setzen 
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed = true;
                presentParams.SwapEffect = SwapEffect.Flip;
                //             presentParams.EnableAutoDepthStencil = true; //with depth buffer
                //             presentParams.AutoDepthStencilFormat = DepthFormat.D24X8; //16 bit depth
                device = new Device(0, DeviceType.Hardware, this, CreateFlags.HardwareVertexProcessing, presentParams);
                //set up the transformation of world coordinates into camera or view space
                device.Transform.View = ViewMatrix;
                //set up the projection transformation using 4 parameters:
                device.Transform.Projection = Matrix.OrthoLH(
                    //field of view = 45 degrees
                    //(float)Math.PI / 4,
                   30f,
                    //spect ratio = heigth / width = 1 = square window
                    //(float)this.Size.Width / (float)this.Size.Height,
                   30f / (float)this.Size.Width * (float)this.Size.Height,
                    //near clipping distance = 0
                   -100f,
                    //far clipping distance = 100
                   100f);
                //Turn off culling, so the user sees the front and back of the triangle
                device.RenderState.CullMode = Cull.Clockwise;
                //Turn off lighting, since the triangle provides its own colors
                device.RenderState.Lighting = false;
                //set up the property that fills the triangle with colors
                device.VertexFormat = CustomVertex.PositionColored.Format;
                if (vertexBuffer != null) vertexBuffer.Dispose(); //free the old vertexBuffer if any
                if (indexBuffer != null) indexBuffer.Dispose(); //free the old indexBuffer if any
                if (lineVertexBuffer != null) lineVertexBuffer.Dispose(); //free the old vertexBuffer if any
                if (lineIndexBuffer != null) lineIndexBuffer.Dispose(); //free the old indexBuffer if any
                //Create a new vertex buffer on the graphics card and connect it to the device.
                vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), VertexCount,
                                                device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format,
                                                Pool.Default);

                lineVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), lineVertexCount,
                                                device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format,
                                                Pool.Default);

                indexBuffer = new IndexBuffer(device, sizeof(int) * IndexCount, 0, Pool.Default, false);
                lineIndexBuffer = new IndexBuffer(device, sizeof(int) * lineIndexCount, 0, Pool.Default, false);


                vertexBuffer.SetData(v, 0, LockFlags.NoDirtyUpdate); //Copy the vertices from main memory to graphics card memory.

                lineVertexBuffer.SetData(v1, 0, LockFlags.NoDirtyUpdate);

                indexBuffer.SetData(index, 0, LockFlags.NoDirtyUpdate);

                lineIndexBuffer.SetData(lineIndex, 0, LockFlags.NoDirtyUpdate);

                device.SetStreamSource(0, vertexBuffer, 0); //Tell the device to use the vertexBuffer on the graphics card.
                device.SetStreamSource(1, lineVertexBuffer, 0);

                return true;
            }
            catch (DirectXException e)
            {
                MessageBox.Show(e.Message);
                return false;
            }
        }
        /// <summary>
        /// Render mesh on device
        /// </summary>
        private void Render()
        {
            if (device == null | network == null) return;
            if (device.Disposed) return;

            //set viewpoint
            device.Transform.View = ViewMatrix;
            // Backbuffer löschen und gleichzeitig die Zeichenfläche schwarz einfärben 
            device.Clear(ClearFlags.Target, System.Drawing.Color.Black, 100.0f, 0);

            // Anfang der Szene
            device.BeginScene();
            //Tell the device to use the vertexBuffer on the graphics card.
            device.SetStreamSource(0, vertexBuffer, 0);
            // An dieser Stelle würden Objekte gerendert werden 
            //drawing neurons
            device.DrawIndexedUserPrimitives(PrimitiveType.TriangleList, 0, VertexCount, VertexCount, index, false, v);
            //drawing connections
            device.DrawIndexedUserPrimitives(PrimitiveType.LineList, 0, lineVertexCount, lineVertexCount/2, lineIndex, false, v1);
            //TODO That's don't work, why?
            //  vertexBuffer.SetData(v, 0, LockFlags.None); //Copy the vertices from main memory to graphics card memory.
            //  indexBuffer.SetData(index, 0, LockFlags.None);
            //      device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 4, 0, VertexCount, 0, 60);
            // Ende der Szene 
            device.EndScene();
            device.Present();
        }
        /// <summary>
        /// Render network at OnPaint event
        /// </summary>
        /// <param name="e">event args</param>
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            Render();
        }
        /// <summary>
        /// Init control
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">event args</param>
        private void SructViewControl_Load(object sender, EventArgs e)
        {
            if (this.Created & network != null)
            {
                if (!this.InitializeGraphics()) // Direct3D initialisieren 
                {
                    MessageBox.Show("Konnte Hardware nicht initialisieren.");
                }
            }
        }
        private void SructViewControl_MouseMove(object sender, MouseEventArgs e)
        {

            switch (e.Button)
            {
                case MouseButtons.None:
                    return;

                case MouseButtons.Left:
                    double dy = (double)(LastRenderedPoint.X - e.X);
                    double dx = -(double)(LastRenderedPoint.Y - e.Y);
                    LastRenderedPoint = e.Location;

                    if (KeyShift_Down)
                    {
                        //TODO Horiz - vert camera move
                        //          SchiftX += -(float)(dx * 0.2d);
                        //          SchiftY += -(float)(dy * 0.2d);
                    }
                    else
                    {
                        AngleY += dx / (float)this.Size.Width * Math.PI;
                        AngleX += dy / (float)this.Size.Width * Math.PI;
                        //TODO the Model flip while rotated.
                        if (AngleX > Math.PI / 2d | AngleX < -Math.PI / 2d) AngleX = 0;
                        if (AngleY > Math.PI | AngleY < -Math.PI) AngleY = 0;
                    }
                    //draw toolstrip label
                    this.toolStripStatusLabel1.Text = "Cam Pos: x " + CameraPosition.X.ToString("F1")
                        + " | y " + CameraPosition.Y.ToString("F1")
                        + " | z " + CameraPosition.Z.ToString("F1")
                        + " | ax " + (AngleX * 180.0f / Math.PI).ToString("F1")
                        + " | ay " + (AngleY * 180.0f / Math.PI).ToString("F1")
                        + " | Scale " + ViewScale.ToString("F1");

                    break;

                case MouseButtons.Right:

                    break;
            }
            //recalculate position
            calcAndRenderNewCameraPosition();
        }
        private void StructViewControl_MouseUp(object sender, MouseEventArgs e)
        {


        }
        private void StructViewControl_MouseDown(object sender, MouseEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Left:
                    LastRenderedPoint = e.Location;
                    return;

                case MouseButtons.Middle:
                    LastRenderedPoint = e.Location;
                    return;

                case MouseButtons.Right:

                    return;

            }
        }
        private void StructViewControl_SizeChanged(object sender, EventArgs e)
        {
            if (device != null & network != null)
            {
                if (!this.InitializeGraphics()) // Direct3D initialisieren 
                {
                    MessageBox.Show("Konnte Hardware nicht re-initialisieren.");
                }
            }
        }
        private void toolStripButtonMaxView_Click(object sender, EventArgs e)
        {
            AngleX = 45f * Math.PI / 180f;
            AngleY = 45f * Math.PI / 180f;
            ViewScale = 1.0f;
            CameraLookAt = new Vector3(Xw, Yw, Zw);
            CamLockal = new Vector3(0f, 0f, -30f);
            device.Transform.Projection = Matrix.OrthoLH(
                   30f * ViewScale,
                   30f * ViewScale / (float)this.Size.Width * (float)this.Size.Height,
                //near clipping distance = 0
                   -100f,
                //far clipping distance = 100
                   100f);
            calcAndRenderNewCameraPosition();
        }
        private void toolStripButtonTopView_Click(object sender, EventArgs e)
        {
            AngleX = 0f;
            AngleY = 0f;
            CameraLookAt = new Vector3(Xw, Yw, Zw);
            CamLockal = new Vector3(0f, 0f, -30f);
            ViewScale = 1f;
            device.Transform.Projection = Matrix.OrthoLH(
                   30f * ViewScale,
                   30f * ViewScale / (float)this.Size.Width * (float)this.Size.Height,
                //near clipping distance = 0
                   -100f,
                //far clipping distance = 100
                   100f);
            calcAndRenderNewCameraPosition();
        }
        private void StructViewControl_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Shift) KeyShift_Down = true;
            switch (e.KeyCode)
            {
                case Keys.PageUp:
                    ViewScale -= 0.5f;
                    break;
                case Keys.PageDown:
                    ViewScale += 0.5f;
                    break;
                default:
                    break;
            }
            calcAndRenderNewCameraPosition();

        }
        private void StructViewControl_KeyUp(object sender, KeyEventArgs e)
        {
            if (!e.Shift) KeyShift_Down = false;
        }
        private void loadnetworkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < v.Length; i += 4)
                v[i].Color = System.Drawing.Color.Red.ToArgb();
            Render();
        }
        /// <summary>
        /// Uterprogramm zur Bearbeitung von event
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="msg">message</param>
        public void handleTickComputed(object sender, string msg)
        {
            fillBuffers();
            Render();
        }
        private void MouseWheelHandler(object sender, MouseEventArgs e)
        {
            ViewScale += (float)e.Delta / 1000.0f;

            device.Transform.Projection = Matrix.OrthoLH(
                   30f * ViewScale,
                   30f * ViewScale / (float)this.Size.Width * (float)this.Size.Height,
                //near clipping distance = 0
                   -100f,
                //far clipping distance = 100
                   100f);
            calcAndRenderNewCameraPosition();
        }
        private void StructViewControl_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Vector3 Ray = new Vector3(0, 0, 0);
            Ray = CameraLookAt - CameraPosition;

            Vector3 Pt, RayPoint, DistancePP;

            Vector3 nearVector = new Vector3(e.X, e.Y, 0);
            Vector3 farVector = new Vector3(e.X, e.Y, 1);

            // Create ray.

            nearVector.Unproject(device.Viewport,
                        device.Transform.Projection,
                        device.Transform.View,
                        device.Transform.World);

            farVector.Unproject(device.Viewport,
                        device.Transform.Projection,
                        device.Transform.View,
                        device.Transform.World);

            Ray = farVector - nearVector;
            Ray.Normalize();

            float MinDist = 10000.0f;
            int SelectedNeuron = -1;

            // is there 4 Points for one neuron
            for (int i = 0; i < v.Length; i += 4)
            {
                //vertex to point
                Pt.X = v[i].X;
                Pt.Y = v[i].Y;
                Pt.Z = v[i].Z;
                //RES it can be better, direct point to vector distance calc
                //construkt plane thru point and coliniar the ray
                Plane Pl = Plane.FromPointNormal(Pt, Ray);
                //find the intersection between ray beginnig from CameraPos and the plane 
                RayPoint = Plane.IntersectLine(
                    Pl,
                    nearVector,
                    farVector);

                this.toolStripStatusLabel1.Text =
                "Pos: x " + RayPoint.X.ToString("F4")
                + " | y " + RayPoint.Y.ToString("F4")
                + " | z " + RayPoint.Z.ToString("F4");

                //vector between point and Ray-point
                DistancePP = Pt - RayPoint;
                //distance between point and Ray-point
                if (DistancePP.Length() < 0.3f)
                {
                    //choose nearest point to camera
                    DistancePP = Pt - CameraPosition;
                    if (DistancePP.Length() < MinDist)
                    {
                        //4 vertex pro neuron
                        SelectedNeuron = (int)i / 4;
                        MinDist = DistancePP.Length();
                    }
                }


            }
            //change color for selected neuron
            if (SelectedNeuron >= 0)
            {
                v[SelectedNeuron * 4].Color = System.Drawing.Color.Cyan.ToArgb();
                addDrawNeuronConnections(SelectedNeuron);
            }

            Render();
        }
        private void toolStripMenuItemAllConnectios_Click(object sender, EventArgs e)
        {
            for (int i = network.NeuronsCount - 1; i > network.inputsCount; i--)
            {
                addDrawNeuronConnections(i);
            }
        }
        private void addDrawNeuronConnections(int NeuronConn)
        {

            int[] inputNeurons;
            float[] inputWeights;

            network[NeuronConn].getInputs(out inputNeurons, out inputWeights);
            //input neurons
            if (inputNeurons[0] == 0) 
                return;

            // +1 is new grid
            int newlineVertexCount = inputNeurons.Length + v1.Length + 1;
            int newlineIndexCount = 2 * inputNeurons.Length + lineIndex.Length;

            CustomVertex.PositionColored[] v1new = new CustomVertex.PositionColored[newlineVertexCount];
            v1.CopyTo(v1new, 0);

            int[] newlineIndex = new int[newlineIndexCount];
            lineIndex.CopyTo(newlineIndex, 0);

            int lastOldVertex = v1.Length - 1;
            int lastOldIndex = lineIndex.Length - 1;

            v1new[lastOldVertex + 1].X = network[NeuronConn].X;
            v1new[lastOldVertex + 1].Y = network[NeuronConn].Y;
            v1new[lastOldVertex + 1].Z = network[NeuronConn].Z;
            v1new[lastOldVertex + 1].Color = System.Drawing.Color.FromArgb(0, 0, 0, 0).ToArgb();

            int p = lastOldIndex + 1;
            for (int m = 1; m < inputNeurons.Length + 1; m++)
            {
                v1new[lastOldVertex + m + 1].X = network[inputNeurons[m - 1]].X;
                v1new[lastOldVertex + m + 1].Y = network[inputNeurons[m - 1]].Y;
                v1new[lastOldVertex + m + 1].Z = network[inputNeurons[m - 1]].Z;
                //RES function
                v1new[lastOldVertex + m + 1].Color = weightToColor(inputWeights, m - 1);

                newlineIndex[p++] = lastOldVertex + 1;
                newlineIndex[p++] = lastOldVertex + m + 1;
            }

            v1 = v1new;
            lineIndex = newlineIndex;
            lineVertexCount = newlineVertexCount;
            lineIndexCount = newlineIndexCount;

            Render();

        }
    }
}
